import { _decorator, Component, Node } from 'cc';
import { ChessCommon } from './ChessCommon';
import { ChessMan } from './ChessMan';
import { ChessUIPanel } from './ChessUIPanel';
const { ccclass, property } = _decorator;

/**
 * https://www.cnblogs.com/hanson666/p/7102069.html
 */
@ccclass('ChessAI')
export class ChessAI {
    /**
     * 历史记录
     */
    public static historyTable = {};
    /**
     * 历史记录
     */
    public static historyBill:string[];

    /**
     * 搜索树
     */
    public static treeDepth:number = 3;
    /**
     * 
     */
    public static autoDepth:number = 3;
    /**
     * 
     */
    public static number:number = 0;

    /**
     * 初始化
     * @param pace 
     */
    public static init(pace:string):number[]{
        var bill = ChessAI.historyBill || ChessCommon.gambit;
        if(bill.length){
            var len = pace.length;
            var arr = [];
            //先搜索棋谱
            for(var i = 0; i < bill.length; i++){
                if(bill[i].slice(0, len) == pace){
                    arr.push(bill[i]);
                }
            }
            //
            if(arr.length){
                var inx = Math.floor(Math.random() * arr.length);
                ChessAI.historyBill = arr;
                var result = arr[inx].slice(len, len + 4).split('');
                return [parseInt(result[0]), parseInt(result[1]), parseInt(result[2]), parseInt(result[3])];
            }else{
                ChessAI.historyBill = [];
            }
        }
        //如果棋谱里面没有，人工智能开始运作
        var initTime = new Date().getTime();
        ChessAI.treeDepth = ChessUIPanel.Instance.depth;
        //AI.treeDepth=4;
        
        ChessAI.number=0;
        // ChessAI.setHistoryTable.lenght = 0
        // console.log("play.my::"+play.my);

        var val = ChessAI.getAlphaBeta(-99999 ,99999, ChessAI.treeDepth, ChessCommon.arr2Clone(ChessUIPanel.Instance.map), ChessUIPanel.Instance.my);
        // console.log("val::"+val.value+"  key::"+val.key);
        //var val = AI.iterativeSearch(com.arr2Clone(play.map),play.my)
        if (!val || val.value == -8888) {
            ChessAI.treeDepth=2;
            val = ChessAI.getAlphaBeta(-99999 ,99999, ChessAI.treeDepth, ChessCommon.arr2Clone(ChessUIPanel.Instance.map), ChessUIPanel.Instance.my);
        }
        //var val = AI.iterativeSearch(com.arr2Clone(play.map),play.my);
        if (val && val.value != -8888) {
            var man = ChessUIPanel.Instance.mans[val.key];
            var nowTime= new Date().getTime();
            ChessUIPanel.Instance.SetLblMsg = "<h3>AI搜索结果：</h3>最佳着法："
                + ChessCommon.createMove(ChessCommon.arr2Clone(ChessUIPanel.Instance.map), man.x, man.y, val.x, val.y) 
                + "<br />搜索深度：" + ChessAI.treeDepth + "<br />搜索分支："
                + ChessAI.number + '个 <br />最佳着法评估：'+ val.value + '分' + ' <br />搜索用时：' + (nowTime-initTime)+'毫秒';
            //
            return [man.x, man.y, val.x, val.y]
        }else {
            return null;	
        }
    }
    /**
     * 迭代加深搜索着法
     * @param map 
     * @param my 
     */
    public static iterativeSearch(map:string[][], my:number):any{
        var timeOut:number = 100;
        var initDepth:number = 1;
        var maxDepth:number = 8;
        ChessAI.treeDepth = 0;
        var initTime:number = new Date().getTime();
        var val = {};
        for(var i = initDepth; i <= maxDepth; i++){
            var nowTime:number = new Date().getTime();
            ChessAI.treeDepth = i;
            ChessAI.autoDepth = i;
            val = ChessAI.getAlphaBeta(-99999, 99999, ChessAI.treeDepth, map, my);
            if(nowTime - initTime > timeOut){
                return val;
            }
        }
        return null;
    }
    /**
     * 取得棋盘上所有棋子
     * @param map 棋盘
     * @param my 
     */
    public static getMapAllMan1(map:string[][], my:number):ChessMan[]{
        var str:string = "";
        var mans:ChessMan[] = [];
        for(var i=0; i < map.length; i++){
            for(var n=0; n < map[i].length; n++){
                var key:string = map[i][n];
                if(ChessCommon.IsValideKey(key) && ChessUIPanel.Instance.mans[key].my == my){
                    mans.push(ChessUIPanel.Instance.mans[key]);
                    str = str + key + " ";
                }
            }
        }
        console.log("[ChessAI] --my::" + my + " len:" + mans.length + " str:" + str);
        return mans;
    }
    //取得棋盘上所有棋子
    public static getMapAllMan(map:string[][], my:number):ChessMan[]{
        var mans=[];
        var str = "";
        for (var i=0; i<map.length; i++){
            for (var n=0; n<map[i].length; n++){
                var key = map[i][n];
                if (key && ChessUIPanel.Instance.mans[key].my == my){
                    ChessUIPanel.Instance.mans[key].x = n;
                    ChessUIPanel.Instance.mans[key].y = i;
                    mans.push(ChessUIPanel.Instance.mans[key])
                    str = str + key + " "
                }
            }
        }
        return mans;
    }
    /**
     * 取得棋谱所有己方棋子的着法
     * @param map 
     * @param my 
     */
    public static getMoves1(map:string[][], my:number):any{
        var manArr = ChessAI.getMapAllMan(map, my);
        var moves = [];
        var foul = ChessUIPanel.Instance.isFoul; //长将着法
        for(var i=0; i < manArr.length; i++){
            var man:ChessMan = manArr[i];
            var val:number[][] = man.blps(map);
            
            for(var n=0; n < val.length; n++){
                var x:number = man.x;
                var y:number = man.y;
                var newX:number = val[n][0];
                var newY:number = val[n][1];
                //如果不是长将着法
                if(null == foul || (foul[0] != x+"" || foul[1] != y+"" || foul[2] != newX+"" || foul[3] != newY+"")){
                    moves.push([x, y, newX, newY, man.key]);
                }
            }
        }
        return moves;
    }

    //取得棋谱所有己方棋子的着法
    public static getMoves(map:string[][], my:number):any{
        var manArr = ChessAI.getMapAllMan(map, my);
        var moves = [];
        var foul=ChessUIPanel.Instance.isFoul;
        for (var i=0; i<manArr.length; i++){
            var man = manArr[i];
            // var val=man.bl(map);
            var val = man.blps(map);
            for (var n=0; n<val.length; n++){
                var x=man.x;
                var y=man.y;
                var newX=val[n][0];
                var newY=val[n][1];
                //如果不是长将着法
                if (foul[0]!=x || foul[1]!=y || foul[2]!=newX || foul[3]!=newY ){
                    moves.push([x,y,newX,newY,man.key]);
                }
            }
        }
        return moves;
    }
    /**
     * A:当前棋手value/B:对手value/depth：层级
     * @param A:当前棋手value 
     * @param B:对手value 
     * @param depth：层级 
     * @param map 
     * @param my 
     */
    public static getAlphaBeta(A:number, B:number, depth:number, map:string[][], my:number){
        if (depth == 0) {
            // console.log("rootKey::value");
            return {"value":ChessAI.evaluate(map , my)}; //局面评价函数; 
        }
        var moves = ChessAI.getMoves(map , my ); //生成全部走法; 
        // console.log("moves.length::"+moves.length);
        //这里排序以后会增加效率
        var rootKey;
        for (var i=0; i < moves.length; i++) {
            //走这个走法;
            var move= moves[i];
            var key = move[4];
            var oldX= move[0];
            var oldY= move[1];
            var newX= move[2];
            var newY= move[3];
            var clearKey = map[ newY ][ newX ]||"";

            map[ newY ][ newX ] = key;
            delete map[ oldY ][ oldX ];
            ChessUIPanel.Instance.mans[key].x = newX;
            ChessUIPanel.Instance.mans[key].y = newY;

            if (clearKey=="j0"||clearKey=="J0") {//被吃老将,撤消这个走法; 
                ChessUIPanel.Instance.mans[key]	.x = oldX;
                ChessUIPanel.Instance.mans[key]	.y = oldY;
                map[ oldY ][ oldX ] = key;
                delete map[ newY ][ newX ];
                if (clearKey){
                    map[ newY ][ newX ] = clearKey;
                }
                return {"key":key,"x":newX,"y":newY,"value":8888};
            }else { 
                var val = -ChessAI.getAlphaBeta(-B, -A, depth - 1, map , -my).value;
                ChessUIPanel.Instance.mans[key]	.x = oldX;
                ChessUIPanel.Instance.mans[key]	.y = oldY;
                map[ oldY ][ oldX ] = key;
                delete map[ newY ][ newX ];
                if (clearKey){
                    map[ newY ][ newX ] = clearKey;
                }
                if (val >= B) { 
                    //将这个走法记录到历史表中; 
                    //AI.setHistoryTable(txtMap,AI.treeDepth-depth+1,B,my);
                    return {"key":key,"x":newX,"y":newY,"value":B}; 
                } 
                if (val > A) {
                    A = val; //设置最佳走法; 
                    // console.log("val > A::"+val+"  AI.treeDepth::"+AI.treeDepth+"  depth::"+depth);
                    if (ChessAI.treeDepth == depth) rootKey={"key":key,"x":newX,"y":newY,"value":A};
                } 
            }
        } 
        //将这个走法记录到历史表中; 
        if (ChessAI.treeDepth == depth) {//已经递归回根了
            if (!rootKey){
                console.log("rootKey::nil");
                //AI没有最佳走法，说明AI被将死了，返回false
                return false;
            }else{
                //这个就是最佳走法;
                // console.log("rootKey::");
                return rootKey;
            }
        }
        return {"key":key,"x":newX,"y":newY,"value":A}; 
    }
    /**
     * 奖着法记录到历史表
     * @param txtMap 
     * @param depth 
     * @param value 
     * @param my 
     */
    public static setHistoryTable(txtMap, depth, value, my){
        ChessAI.historyTable[txtMap] = {depth:depth, value:value} 
    }
    /**
     * 评估棋局 取得棋盘双方棋子价值差
     * @param map 
     * @param my 
     */
    public static evaluate(map:string[][], my:number):number{
        var val=0;
        for (var i=0; i < map.length; i++){
            for (var n=0; n < map[i].length; n++){
                var key = map[i][n];
                if (ChessCommon.IsValideKey(key)){
                    var man = ChessUIPanel.Instance.mans[key];
                    val += man.value[i][n] * man.my;
                }
            }
        }
        //val+=Math.floor( Math.random() * 10);  //让AI走棋增加随机元素
        //com.show()
        //z(val*my)
        ChessAI.number++;
        return val * my;
    }
    /**
     * 评估棋局 取得棋盘双方棋子价值差
     * @param map 
     * @param my 
     */
    public static evaluate1(map:string[][], my:number):number{
        var val=0;
        for (var i in ChessUIPanel.Instance.mans){
            var man:ChessMan = ChessUIPanel.Instance.mans[i];
            if (man.isShow){
                val += man.value[man.y][man.x] * man.my;
            }
        }
        //val+=Math.floor( Math.random() * 10);  //让AI走棋增加随机元素
        //com.show()
        //z(val*my)
        ChessAI.number++;
        return val * my;
    }
}

